#include "RpcWebClient.h"
#include "RpcDcClient.h"
#include "SE_Exception.h"


static CRITICAL_SECTION     __G_CS__RpcWebClient;
static RpcWebClient         __G_RpcWebClient;

static CRITICAL_SECTION     __G_CS__RpcDcClient;
static RpcDcClient          __G_RpcDcClient;


BOOL WINAPI DllMain(__in HINSTANCE hInstance, __in DWORD dwReason, __in LPVOID lpReserved);
BOOL WINAPI RpcWebClientConnect(__in_opt LPCSTR svcAddress, __in_opt LPCSTR svcEndpoint, __in BOOL fIsDrawMode);
VOID WINAPI RpcWebClientDisconnect();
BOOL WINAPI RpcWebClientIoctl(__in DWORD ioctl, __in DWORD sizeIn, __in BYTE *bufferIn, __in DWORD sizeOut, __out BYTE *bufferOut);
BOOL WINAPI RpcDcClientConnect(__in_opt LPCSTR svcAddress, __in_opt LPCSTR webSvcEndpoint, __in_opt LPCSTR dcSvcEndpoint);
VOID WINAPI RpcDcClientDisconnect();
BOOL WINAPI RpcDcClientIoctl(__in DWORD ioctl, __in DWORD sizeIn, __in BYTE *bufferIn, __in DWORD sizeOut, __out BYTE *bufferOut);


BOOL WINAPI DllMain(__in HINSTANCE hInstance, __in DWORD dwReason, __in LPVOID lpReserved) {

    SE_Exception::Initialize();

    switch(dwReason) {

    case DLL_PROCESS_ATTACH:
        {
            DisableThreadLibraryCalls(hInstance);

            InitializeCriticalSection( &__G_CS__RpcWebClient);
            InitializeCriticalSection( &__G_CS__RpcDcClient);
        } break;

    case DLL_PROCESS_DETACH:
        {

            RpcWebClientDisconnect();
            DeleteCriticalSection( &__G_CS__RpcWebClient);

            RpcDcClientDisconnect();
            DeleteCriticalSection( &__G_CS__RpcDcClient);
        } break;
    default:
        { }
    }

    return TRUE;
}

BOOL WINAPI RpcWebClientConnect(__in_opt LPCSTR svcAddress, __in_opt LPCSTR svcEndpoint, __in BOOL fIsDrawMode) {

    BOOL        fResult = FALSE;
    std::string strSvcAddress,
                strSvcEndpoint,
                strInfo;
    RpcWebClient::tag_eConnType connType;


    SE_Exception::Initialize();

    RpcWebClientDisconnect();

    EnterCriticalSection( &__G_CS__RpcWebClient );

    try {

        strSvcAddress = (svcAddress) ? svcAddress : "127.0.0.1";

        strSvcEndpoint = (svcEndpoint) ? svcEndpoint : "4592";

        connType = (fIsDrawMode) ? RpcWebClient::eConnTypeDraw : RpcWebClient::eConnTypeView;

        if (__G_RpcWebClient.Configure(strSvcAddress, strSvcEndpoint, connType) ) {

            fResult = __G_RpcWebClient.Connect();
        }
    }
    catch(SE_Exception e) {

        e.InqDescription(strInfo);

        printf(
            "[!] %s(): Exception occured: {code: %08xh; info: '%s'}\n", 
            __FUNCTION__, 
            e.InqSE(), 
            strInfo.c_str()
            );
    }

    LeaveCriticalSection( &__G_CS__RpcWebClient );

    return fResult;
}

VOID WINAPI RpcWebClientDisconnect() {

    std::string strInfo;


    SE_Exception::Initialize();

    EnterCriticalSection(&__G_CS__RpcWebClient);

    try {
    
        __G_RpcWebClient.Disconnect();
    }
    catch(SE_Exception e) {

        e.InqDescription(strInfo);

        printf(
            "[!] %s(): Exception occured: {code: %08xh; info: '%s'}\n", 
            __FUNCTION__, 
            e.InqSE(), 
            strInfo.c_str()
            );
    }

    LeaveCriticalSection(&__G_CS__RpcWebClient);

    return;
}

BOOL WINAPI RpcWebClientIoctl(__in DWORD ioctl, __in DWORD sizeIn, __in BYTE *buffIn, __in DWORD sizeOut, __out BYTE *buffOut) {

    BOOL    fResult = FALSE;
    long    status  = S_OK;
    std::string strInfo;


    EnterCriticalSection( &__G_CS__RpcWebClient );

    SE_Exception::Initialize();

    try {

        if (__G_RpcWebClient.InqIsConnected()) {
        
            fResult = __G_RpcWebClient.ExecuteRequest(ioctl, sizeIn, buffIn, sizeOut, buffOut, &status);
        }
    }
    catch(SE_Exception e) {

        e.InqDescription(strInfo);

        printf(
            "[!] %s(): Exception occured: {code: %08xh; info: '%s'}\n", 
            __FUNCTION__, 
            e.InqSE(), 
            strInfo.c_str()
            );
    }

    LeaveCriticalSection( &__G_CS__RpcWebClient );

    return fResult;
}

BOOL WINAPI RpcDcClientConnect(__in_opt LPCSTR svcAddress, __in_opt LPCSTR webSvcEndpoint, __in_opt LPCSTR dcSvcEndpoint) {

    BOOL    fResult = FALSE;
    std::string strSvcAddress,
                strWebSvcEndpoint,
                strDcSvcEndpoint,
                strInfo;


    SE_Exception::Initialize();

    RpcDcClientDisconnect();

    EnterCriticalSection( &__G_CS__RpcDcClient );

    try {

        strSvcAddress = (svcAddress) ? svcAddress : "127.0.0.1";

        strWebSvcEndpoint = (webSvcEndpoint) ? webSvcEndpoint : "4592";

        strDcSvcEndpoint = (dcSvcEndpoint) ? dcSvcEndpoint : "14592";


        if (__G_RpcDcClient.Configure(strSvcAddress, strWebSvcEndpoint, strDcSvcEndpoint) ) {

            fResult = __G_RpcDcClient.Connect();
        }
    }
    catch(SE_Exception e) {

        e.InqDescription(strInfo);

        printf(
            "[!] %s(): Exception occured: {code: %08xh; info: '%s'}\n", 
            __FUNCTION__, 
            e.InqSE(), 
            strInfo.c_str()
            );
    }

    LeaveCriticalSection( &__G_CS__RpcDcClient );

    return fResult;
}

VOID WINAPI RpcDcClientDisconnect() {
    
    std::string strInfo;


    SE_Exception::Initialize();

    EnterCriticalSection( &__G_CS__RpcDcClient );

    try {

        __G_RpcDcClient.Disconnect();
    }
    catch(SE_Exception e) {

        e.InqDescription(strInfo);

        printf(
            "[!] %s(): Exception occured: {code: %08xh; info: '%s'}\n", 
            __FUNCTION__, 
            e.InqSE(), 
            strInfo.c_str()
            );
    }

    LeaveCriticalSection( &__G_CS__RpcDcClient );

    return;
}

BOOL WINAPI RpcDcClientIoctl(__in DWORD ioctl, __in DWORD sizeIn, __in BYTE *bufferIn, __in DWORD sizeOut, __out BYTE *bufferOut) {

    BOOL    fResult = FALSE;
    long    status  = S_OK;
    std::string strInfo;
    

    SE_Exception::Initialize();

    EnterCriticalSection( &__G_CS__RpcDcClient );

    try {

        if (__G_RpcDcClient.InqIsConnected()) {

            fResult = __G_RpcDcClient.ExecuteRequest(ioctl, sizeIn, bufferIn, sizeOut, bufferOut, &status);
        }
    }
    catch(SE_Exception e) {

        e.InqDescription(strInfo);

        printf(
            "[!] %s(): Exception occured: {code: %08xh; info: '%s'}\n", 
            __FUNCTION__, 
            e.InqSE(), 
            strInfo.c_str()
            );
    }

    LeaveCriticalSection( &__G_CS__RpcDcClient );

    return fResult;
}